﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace Casamiel.Common.Http
{
    /// <summary>
    /// 
    /// </summary>
    public class StandardHttpClient : IHttpClient
    {
        private readonly IHttpClientFactory _HttpClientFactory;
        private readonly HttpClient _client;
        private ILogger<StandardHttpClient> _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private string useragent;
        private string ip;
        public StandardHttpClient(IHttpClientFactory httpClientFactory,ILogger<StandardHttpClient> logger, IHttpContextAccessor httpContextAccessor)
        {
            _HttpClientFactory = httpClientFactory;
            //_client = new HttpClient();
            //_client.Timeout = new TimeSpan(0, 0, 30);
            //_client.DefaultRequestHeaders.Connection.Add("keep-alive");
            _client = _HttpClientFactory.CreateClient();
            _logger = logger;
            _httpContextAccessor = httpContextAccessor;
            useragent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"];
            //Console.WriteLine(useragent);
            //_client.DefaultRequestHeaders.UserAgent = useragent;
            ip = _httpContextAccessor.HttpContext.Request.GetUserIp();
         //  _client.DefaultRequestHeaders.Add("UserAgent", _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString());
           //  _client.DefaultRequestHeaders.Add("X-Forwarded-For", _httpContextAccessor.HttpContext.Request.GetUserIp());
        }
        public HttpClient MyClient
        {
            get { return _client; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="authorizationToken"></param>
        /// <param name="token"></param>
        /// <param name="authorizationMethod"></param>
        /// <returns></returns>
        public async Task<string> GetStringAsync(string uri, string authorizationToken = null, string token = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
            requestMessage.Headers.Add("UserAgent", useragent);
            requestMessage.Headers.Add("X-Forwarded-For", ip);
            requestMessage.Headers.Add("ClientId", "wx");
            
            SetAuthorizationHeader(requestMessage);

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            if (token != null)
            {
                requestMessage.Headers.Add("u-token", token);
            }
         
            var response = await _client.SendAsync(requestMessage);

            return await response.Content.ReadAsStringAsync();
        }

        private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string token = null, string authorizationMethod = "Bearer")
        {
            if (method != HttpMethod.Post && method != HttpMethod.Put)
            {
                throw new ArgumentException("Value must be either post or put.", nameof(method));
            }

            // a new StringContent must be created for each retry
            // as it is disposed after each call

            var requestMessage = new HttpRequestMessage(method, uri);
            requestMessage.Headers.Add("X-Forwarded-For", ip);
            requestMessage.Headers.Add("UserAgent", useragent);
            requestMessage.Headers.Add("ClientId", "wx");
            SetAuthorizationHeader(requestMessage);

            requestMessage.Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json");

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            if (token != null)
            {
                requestMessage.Headers.Add("u-token", token);
            }
            
            var response = await _client.SendAsync(requestMessage);

            // raise exception if HttpResponseCode 500
            // needed for circuit breaker to track fails

            if (response.StatusCode == HttpStatusCode.InternalServerError)
            {
                throw new HttpRequestException();
            }

            return response;
        }


        public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string token = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, token, authorizationMethod);
        }

        public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string token = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, token, authorizationMethod);
        }
        public async Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string token = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);

            SetAuthorizationHeader(requestMessage);
            requestMessage.Headers.Add("X-Forwarded-For", ip);
            requestMessage.Headers.Add("UserAgent", useragent);
            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            if (token != null)
            {
                requestMessage.Headers.Add("u-token", token);
            }
           

            return await _client.SendAsync(requestMessage);
        }

        private void SetAuthorizationHeader(HttpRequestMessage requestMessage)
        {
            var authorizationHeader = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
            if (!string.IsNullOrEmpty(authorizationHeader))
            {
                requestMessage.Headers.Add("Authorization", new List<string>() { authorizationHeader });
            }
        }
    }
}
